// 链式代理
// 支持http代理，支持Basic认证。

const net = require('net');

// 代理服务器链，理论上可以链无数个。
const proxies = [
    {
        // V2Ray提供的本地代理服务，会连接到公开的代理服务器。
        host: '127.0.0.1',
        port: 10809
    },
    {
        // VPS
        host: '1.1.1.1',
        port: 11111,
        username: '1',
        password: '1'
    }
]; // 根据需要进行修改

// 解析连接请求
// CONNECT www.google.com:443 HTTP/1.1
// Host: www.google.com:443
// Proxy-Connection: keep-alive
// User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36
function parseRequest(data) {
    let result = {};
    let s = data.toString();
    let lines = s.split(/\r\n/);
    let items = lines[0].split(' ');
    result.method = items[0];  // CONNECT
    result.host = items[1];    // www.google.com:443
    result.version = items[2]; // HTTP/1.1
    result.headers = {};
    for (let i = 1; i < lines.length; i++) {
        items = lines[i].split(/: /, 2);
        if (items.length == 2) {
            result.headers[items[0]] = items[1];
        }
    }
    return result;
}

// 解析连接响应
// HTTP/1.1 200 OK
// HTTP/1.1 407 Proxy Authentication Required
// Proxy-Authenticate: Basic realm="proxy"
function parseResponse(data) {
    let result = {};
    let s = data.toString();
    let lines = s.split(/\r\n/);
    let items = lines[0].split(' ', 3);
    result.version = items[0];
    result.status = items[1];
    result.message = items.length == 3 ? items[2] : '';
    return result;
}

function isFinished(data) {
    return data.length >= 4
        && data[data.length - 4] == 0x0D
        && data[data.length - 3] == 0x0A
        && data[data.length - 2] == 0x0D
        && data[data.length - 1] == 0x0A;
}

function makeConnectRequest(proxies, index, target) {
    let host = null;
    if (index < proxies.length) {
        host = proxies[index].host + ':' + proxies[index].port;
        console.log(`${target} 正在连接${index + 1}级代理 ${host}`);
    } else {
        console.log(`${target} 正在连接`);
        host = target;
    }
    let request = `CONNECT ${host} HTTP/1.1\r\n`;
    request += `Proxy-Connection: keep-alive\r\n`;
    // 连接第i级代理的请求是发给第i-1级的，所以需要第i-1级的用户名和密码。
    if (proxies[index - 1].username && proxies[index - 1].password) {
        let authorization = proxies[index - 1].username + ':' + proxies[index - 1].password;
        authorization = Buffer.from(authorization).toString('base64');
        request += `Proxy-Authorization: Basic ${authorization}\r\n`;
    }
    request += '\r\n';
    return request;
}

const server = net.createServer();

server.on('connection', (socket) => {
    // 浏览器连接建立
    let buffer = Buffer.from([]);
    let cb = (data) => {
        // 读取请求
        buffer = Buffer.concat([buffer, data]);
        if (isFinished(buffer)) {
            // 请求接收完毕
            // 取消data事件监听
            socket.off('data', cb);
            // 解析请求内容
            let request = parseRequest(buffer);
            if (request.method != 'CONNECT') {
                // 并非连接请求，直接断开连接。
                socket.end();
                return;
            }

            if (proxies.length == 0) {
                // 不使用代理，直接连接目标服务器。
                let address = request.host.split(':');
                console.log(`${request.host} 正在连接`);
                let socket2 = net.connect({ host: address[0], port: parseInt(address[1]) }, () => {
                    console.log(`${request.host} 连接成功`);
                    socket.write('HTTP/1.1 200 OK\r\n\r\n');
                    socket2.pipe(socket).pipe(socket2);
                });
                socket2.on('error', (err) => {
                    console.error('服务器连接异常', err);
                });
                return;
            }

            let index = 0;
            console.log(`${request.host} 正在连接${index + 1}级代理 ${proxies[index].host}:${proxies[index].port}`);
            let socket2 = net.connect({ host: proxies[index].host, port: proxies[index].port }, () => {
                let buffer = Buffer.from([]);
                let socket2CB = (data) => {
                    buffer = Buffer.concat([buffer, data]);
                    if (isFinished(buffer)) {
                        let response = parseResponse(buffer);
                        buffer = Buffer.from([]);
                        switch (response.status) {
                            case '200':
                                // 连接成功
                                index++;
                                if (index > proxies.length) {
                                    console.log(`${request.host} 连接成功`);
                                    // 取消data事件监听
                                    socket2.off('data', socket2CB);
                                    // 向浏览器发送消息，表示连接成功。
                                    socket.write('HTTP/1.1 200 OK\r\n\r\n');
                                    // 建立隧道
                                    socket2.pipe(socket).pipe(socket2);
                                } else {
                                    console.log(`${request.host} 连接到${index}级代理 ${proxies[index - 1].host}:${proxies[index - 1].port}`);
                                    socket2.write(makeConnectRequest(proxies, index, request.host));
                                }
                                break;
                            case '407':
                                console.log(`${request.host} ${index}级代理用户名和密码错误`)
                                socket2.end();
                                socket.end();
                                break;
                            default:
                                // 接收到其他状态码
                                console.log(`${request.host} ${index}级代理返回异常状态。${response.status} ${response.message}`);
                                socket2.end();
                                socket.end();
                                break;
                        }
                    }
                };

                socket2.on('data', socket2CB);
                socket2.on('error', (err) => {
                    console.error(`${request.host} 代理服务器连接异常`, err);
                    socket.end();
                });

                console.log(`${request.host} 连接到${index + 1}级代理${proxies[index].host}:${proxies[index].port}`);
                index++;
                socket2.write(makeConnectRequest(proxies, index, request.host));
            });
        }
    };
    socket.on('data', cb);

    socket.on('error', (err) => {
        console.error('浏览器连接异常', err);
    });
});

// 监听端口
server.listen(10813, () => {
    console.log('代理服务器已启动');
});